package com.lecyon.farm.config;

import com.baomidou.mybatisplus.core.parser.ISqlParser;
import com.baomidou.mybatisplus.core.parser.ISqlParserFilter;
import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import com.lecyon.farm.common.constant.CommonConstant;
import com.lecyon.farm.util.RedisUtils;
import com.lecyon.farm.util.StringHelper;
import com.lecyon.farm.util.ValidateUtils;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import org.apache.commons.collections.CollectionUtils;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author Yao Zheng
 * @since 2019/07/27
 */
@Configuration
@MapperScan("com.lecyon.farm.mapper")
public class MybatisPlusConfig {

    private HttpSession httpSession;

    private RedisUtils redisUtils;

    @Autowired
    public void setHttpSession(HttpSession httpSession) {
        this.httpSession = httpSession;
    }

    @Autowired
    public void setRedisUtils(RedisUtils redisUtils) {
        this.redisUtils = redisUtils;
    }

    /**
     * 多租户属于 SQL 解析部分，依赖 MP 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {

        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();

        /**
         * 【测试多租户】 SQL 解析处理拦截器<br>
         * 这里固定写成住户 1 实际情况你可以从cookie读取，因此数据看不到 【 麻花藤 】 这条记录（ 注意观察 SQL ）<br>
         */
        List<ISqlParser> sqlParserList = new ArrayList<>();
        paginationInterceptor.setSqlParserList(sqlParserList);
        TenantSqlParser tenantSqlParser = new TenantSqlParser();
        TenantHandler tenantHandler = new TenantHandler() {
            @Override
            public Expression getTenantId(boolean where) {
                // 该 where 条件 3.2.0 版本开始添加的，用于分区是否为在 where 条件中使用
                // 此判断用于支持返回多个租户 ID 场景，具体使用查看示例工程
                String token = null;
                Subject subject = SecurityUtils.getSubject();
                if (ValidateUtils.isNotNullOrEmpty(subject)) {
                    token = (String) subject.getPrincipal();
                }
                String tenantId = null;
                if (StringHelper.isEmpty(token)) {
                    subject = SecurityUtils.getSubject();
                    Session session = subject.getSession();
                    tenantId = (String) session.getAttribute("currentOwner");
                }
                if (StringHelper.isEmpty(tenantId) && redisUtils.hasKey(token)) {
                    tenantId = (String) redisUtils.get(token);
                }
                if (StringHelper.isEmpty(tenantId)) {
                    tenantId = (String) httpSession.getAttribute("currentOwner");
                }
                return new StringValue(tenantId);
            }

            @Override
            public String getTenantIdColumn() {
                return CommonConstant.SYSTEM_TENANT_ID_FIELD;
            }

            @Override
            public boolean doTableFilter(String tableName) {
                // 这里可以判断是否过滤表
                List<String> tableFilterNameList = Arrays.asList(CommonConstant.TABLE_FILTER_NAME_LIST);
                List<String> tableFilterPrefixList = Arrays.asList(CommonConstant.TABLE_FILTER_PREFIX_LIST);
                if (StringHelper.isNotEmpty(tableName)) {
                    if (CollectionUtils.isNotEmpty(tableFilterNameList) && tableFilterNameList.contains(tableName)) {
                        return true;
                    }
                    if (CollectionUtils.isNotEmpty(tableFilterPrefixList)) {
                        for (String prefix : tableFilterPrefixList) {
                            if (tableName.contains(prefix)) {
                                return true;
                            }
                        }
                    }
                }
                return true;
            }
        };
        tenantSqlParser.setTenantHandler(tenantHandler);
        sqlParserList.add(tenantSqlParser);
        paginationInterceptor.setSqlParserList(sqlParserList);
        paginationInterceptor.setSqlParserFilter(new ISqlParserFilter() {
            @Override
            public boolean doFilter(MetaObject metaObject) {
                MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
                // 过滤自定义查询此时无租户信息约束【 麻花藤 】出现
                /**
                 if ("com.baomidou.springboot.mapper.UserMapper.selectListBySQL".equals(ms.getId())) {
                 return true;
                 }
                 */
                return true;
            }
        });
        // 开启 count 的 join 优化,只针对 left join !!!
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }

}
